package com.icezzz.pdm_parser;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;

public class PdmXmlParser {

    public static void exportXls(String path, String xlsOut) {
        Pair<List<List<List<String>>>, List<String>> data = parser(path);
        List<List<List<String>>> list = data.getKey();
        List<String> tableNames = data.getValue();
        writeXls(xlsOut, list, tableNames);
    }

    private static Pair<List<List<List<String>>>, List<String>> parser(String path) {
        Pair<List<List<List<String>>>, List<String>> pair = null;
        Document document = document(path);
        NodeList modelList = document.getElementsByTagName("Model");
        Node model = modelList.item(0);
        NodeList childNodes = model.getChildNodes();
        Node rootObject = firstNode(childNodes, "o:RootObject");
        Node children = firstNode(rootObject, "c:Children");
        Node modelInner = firstNode(children, "o:Model");
        Node tables = firstNode(modelInner, "c:Tables");
        List<Node> tablesList = childNodes(tables, "o:Table");
        List<List<List<String>>> list = new ArrayList<>();
        List<String> tableNames = new ArrayList<>();
        for (int i = 0; i < tablesList.size(); i++) {
            List<List<String>> tableData = new ArrayList<>();
            List<String> columnTitleData = title();
            tableData.add(columnTitleData);
            Node table = tablesList.get(i);
            String name = text(table, "a:Name");
            String code = text(table, "a:Code");
            String comment = text(table, "a:Comment");
            String primaryKey = text(table, "c:PrimaryKey");
            String keys = text(table, "c:Keys");
            String tableInfo = "name = " + name + ", comment = " + comment;
            System.out.println(tableInfo);
            Node columns = firstNode(table, "c:Columns");
            List<Node> columnsList = childNodes(columns, "o:Column");
            int columnsLength = columnsList.size();
            String tableName = tableName(name, code, comment);
            tableNames.add(tableName);
            for (int j = 0; j < columnsLength; j++) {
                List<String> columnData = new ArrayList<>();
                Node column = columnsList.get(j);
                String columnName = text(column, "a:Name");
                String columnCode = text(column, "a:Code");
                String columnComment = text(column, "a:Comment");
                String columnDefaultValue = text(column, "a:DefaultValue");
                String columnDataType = text(column, "a:DataType");
                String columnLength = text(column, "a:Length");
                columnData.add(columnName);
                columnData.add(columnCode);
                columnData.add(columnComment);
                columnData.add(columnDefaultValue);
                columnData.add(columnDataType);
                columnData.add(columnLength);
                tableData.add(columnData);
            }
            list.add(tableData);
        }
        pair = new Pair<>(list, tableNames);
        return pair;
    }

    private static String tableName(String name, String code, String comment) {
        if (StrUtil.isNotBlank(comment)) {
            comment = StrUtil.removeAllLineBreaks(comment);
            return comment;
        } else if (StrUtil.isNotBlank(code)) {
            return code;
        } else if (StrUtil.isNotBlank(name)) {
            return name;
        }
        return null;
    }

    private static void writeXls(String xls, List<List<List<String>>> list, List<String> tableNames) {
        ExcelWriter writer = ExcelUtil.getWriter(xls);
        for (int i = 0; i < list.size(); i++) {
            List<List<String>> table = list.get(i);
            if (table.size() > 1) {
                String sheetName = RandomUtil.randomNumbers(5);
                if (i < tableNames.size()) {
                    sheetName = tableNames.get(i);
                }
                writer.setSheet(sheetName);
                writer.write(table, true);
            }
        }
        writer.close();
    }

    private static List<String> title() {
        List<String> columnData = new ArrayList<>();
        columnData.add("name");
        columnData.add("code");
        columnData.add("comment");
        columnData.add("defaultValue");
        columnData.add("dataType");
        columnData.add("length");
        return columnData;
    }

    private static String text(Node node, String nodeName) {
        NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            short nodeType = item.getNodeType();
            if (Node.ELEMENT_NODE == nodeType) {
                String nodeNameCur = item.getNodeName();
                if (nodeNameCur.equals(nodeName)) {
                    return item.getTextContent();
                }
            }
        }
        return null;
    }

    private static List<Node> childNodes(Node node, String nodeName) {
        List<Node> list = new ArrayList<>();
        NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            short nodeType = item.getNodeType();
            if (Node.ELEMENT_NODE == nodeType) {
                String nodeNameCur = item.getNodeName();
                if (nodeNameCur.equals(nodeName)) {
                    list.add(item);
                }
            }
        }
        return list;
    }

    private static Node firstNode(NodeList childNodes, String nodeName) {
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            short nodeType = item.getNodeType();
            if (Node.ELEMENT_NODE == nodeType) {
                String nodeNameCur = item.getNodeName();
                if (nodeNameCur.equals(nodeName)) {
                    return item;
                }
            }
        }
        return null;
    }

    private static Node firstNode(Node node, String nodeName) {
        NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            short nodeType = item.getNodeType();
            if (Node.ELEMENT_NODE == nodeType) {
                String nodeNameCur = item.getNodeName();
                if (nodeNameCur.equals(nodeName)) {
                    return item;
                }
            }
        }
        return null;
    }

    private static Document document(String path) {
        try {
            DocumentBuilder newDocumentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            File file = new File(path);
            Document document = newDocumentBuilder.parse(file);
            return document;
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
